﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using QQ2564874169.Core.Lock;
using QQ2564874169.RelationalSql;

namespace WebDemo.Services
{
    public abstract class ServiceBo : DomainObject<ServiceBo>
    {
        protected IDbQuery DbQuery { get; private set; }
        protected IDbExecute DbExecute { get; private set; }
        private ServiceContext _context;

        protected abstract void OnExecute(ServiceContext context);

        protected virtual void OnBefore(ServiceBoBeforeArgs args)
        {
        }

        protected string GetIdempotentKey(params object[] args)
        {
            var list = new List<object> { GetType().FullName };
            list.AddRange(args.ToArray());
            return string.Join(".", list);
        }

        protected internal sealed override ServiceBo OnUse(DomainContext context, object state = null)
        {
            var before = new ServiceBoBeforeArgs(_context = (ServiceContext) state);

            OnBefore(before);

            if (before.Cancel == false)
            {
                DbQuery = before.Context.Container.Resolve<IDbQuery>();
                DbExecute = before.Context.Container.Resolve<IDbExecute>();

                if (before.IdempotentKey != null)
                {
                    using (Exlock(before.IdempotentKey))
                    {
                        OnExecute(before.Context);
                    }
                }
                else
                {
                    OnExecute(before.Context);
                }
            }
            return this;
        }

        protected ILockspace Exlock(string key, string ex = null)
        {
            return new ExceptionLockspace(_context.Container.Resolve<ILocker>(), key, ex);
        }

        protected ILockspace Queuelock(string key, int? timeout = null)
        {
            return new QueueLockspace(_context.Container.Resolve<ILocker>(), key, timeout);
        }
    }

    public class ServiceBoBeforeArgs : EventArgs
    {
        public ServiceContext Context { get; }
        /// <summary>
        /// 幂等Key，如果不为空则作为异常锁的Key。
        /// </summary>
        public string IdempotentKey { get; set; }
        /// <summary>
        /// 是否取消执行OnExecute。
        /// </summary>
        public bool Cancel { get; set; }

        public ServiceBoBeforeArgs(ServiceContext context)
        {
            Context = context;
        }
    }
}